var gbookmarks_href = "https://www.google.com/bookmarks/?output=xml&num=10000";
var poll_timeout = 600000;

var otherBookmarks;
var bookmarksBar;
var userFolder;
var userFolderName = "Google Bookmarks";

var delimiter = "/";
var sortorder = "A";
var rootfolder;
var checkfrequency = 60;
var check_timer;
var showPageAction = "true";

var oldNodes;

//Give up loading bookmarks after 1 minute
var giveUp_timeout = 1*60*1000;

function getTreeNode(title, url, date) {
   return {'title':title, 'url':url, 'date':date, 'children':[] };
}

// root is a tree node
// path is an array  of the form child/child/parent
// node is the node to add
function addTreeNode(root, path, node) {
   if (path.length == 0) {
      root.children.push(node);
   } else {
      var currentLevel = path.shift();
      var found = false;
      for( var i=0; i< root.children.length; i++) {
          if (root.children[i].title == currentLevel) {
              addTreeNode(root.children[i], path, node);
              found = true;
          }
      }
      
      if (! found) {
          var newNode = getTreeNode(currentLevel, undefined, 0);
          root.children.push(newNode);
          addTreeNode(newNode, path, node);
      }
   }
}

function printTree(root) {
   return printTreeR(root, "");
}

function printTreeR(root, path) {
   if (root.children.length == 0) {
       return path + "/" + root.title + " - " + root.date + "\n";
   } else {
      var retval = "";
      retval = retval + root.title + " - " + root.date + "\n";
       for (var i = 0; i< root.children.length; i++) {
           retval = retval + printTreeR(root.children[i], path + "/" + root.title);
       }
       return retval;
   }
}

function compareText(a, b) {
    var res = 0;
    var nameA = a.title.toLowerCase();
    var nameB = b.title.toLowerCase();
    if (nameA == userFolderName.toLowerCase()) { res = 1 }
    if (nameB == userFolderName.toLowerCase()) { res = -1 }
    if (nameA == "other bookmarks") { res = 1 }
    if (nameB == "other bookmarks") { res = -1 }
    if (nameA == "bookmarks bar") { res = 1 }
    if (nameB == "bookmarks bar") { res = -1 }
    if (nameA < nameB) { res = -1 }
    if (nameA > nameB) { res = 1 }
    //console.log("compareText: Comparing "+a.title+" and "+b.title+", res="+res);
    return res;
}

function compareDate(a, b) {
    if (a.date == b.date) {
       return compareText(a,b);
    } else {
       return b.date - a.date;
    }
}

function findNodeRecursive(node, treeNode) {
  //console.log("findNodeRecursive: node.title="+node.title+" treeNode.title="+treeNode.title);
  try{
    if (treeNode.title == node.title) {
	  return treeNode;
    } else if (treeNode.children) {
	for (var i = 0; i< treeNode.children.length; i++) {
	    var res = findNodeRecursive(node, treeNode.children[i]);
	    if (res != undefined) {
		return res;
	    }
	}
    }
   } catch (e) {}
   return undefined;
}

//Preserve original order
function compareOrigOrder(a, b) {
  var res = 0;
  var oldA = findNodeRecursive(a, oldNodes[0]);
  var oldB = findNodeRecursive(b, oldNodes[0]);

  if (oldA == undefined || oldB == undefined) {
    res = 0;
  } else {
    res = oldA.index - oldB.index;
  }
  //console.log("compareOrigOrder: Comparing "+a.title+" ("+oldA.title+") and "+b.title+" ("+oldB.title+"), res="+res);
  return res;
}

function createBookmarkTreeNoRoot(tree, parentId) {
  //console.log("createBookmarkTreeNoRoot: tree="+tree.title);
    if (sortorder == "D") {
        tree.children.sort(compareDate);
    } else if (sortorder == "A") {
        tree.children.sort(compareText);
    } else if (sortorder == "U") {
        tree.children.sort(compareOrigOrder);
    }
    
    for (var i = 0; i< tree.children.length; i++) {
       createBookmarkTree(tree.children[i], parentId);
    }
}

function createBookmarkTree(tree, parentId) {
    if ((tree.title == "Bookmarks bar") && (userFolderName != "Google Bookmarks")) {
        createBookmarkTreeNoRoot(tree, bookmarksBar);
    } else if ((tree.title == "Other bookmarks") && (userFolderName != "Google Bookmarks")) {
        createBookmarkTreeNoRoot(tree, otherBookmarks);
    } else if (tree.title == "Google Bookmarks") {
        createBookmarkTreeNoRoot(tree, userFolder);
    } else {
        chrome.bookmarks.create({
            'parentId': parentId,
            'title': tree.title,
            'url': tree.url
        }, function(newbookmark) {

	  //console.log("createBookmarkTree: tree="+tree.title);
            if (sortorder == "D") {
                tree.children.sort(compareDate);
            } else if (sortorder == "A") {
		tree.children.sort(compareText);
	    } else if (sortorder == "U") {
		tree.children.sort(compareOrigOrder);
	    }

            for (var i = 0; i < tree.children.length; i++) {
                createBookmarkTree(tree.children[i], newbookmark.id);
            }
        });
    }
}

function deleteFolder(folder, callback) {
    for (var i = 0; i < folder.children.length; i++) {
        chrome.bookmarks.removeTree(folder.children[i].id, function() { });
    }
    callback();
}

function deleteFolderId(folderId, callback) {
   chrome.bookmarks.get(folderId, function(result) {
      chrome.bookmarks.getChildren(result[0].id, function(result) {

         for (var i = 0; i < result.length; i++) {
            chrome.bookmarks.removeTree(result[i].id, function() {
            });
         }
         callback();
      });
   });
}

function deleteBookmarks(callback) {
   chrome.bookmarks.getTree(function(results) {
       otherbookmarks = results[0].children[1];
       bookmarksbar = results[0].children[0];
       deleteFolder(bookmarksbar, function() {
          deleteFolder(otherbookmarks, callback);
       });
       
   });
}

function findFolder(folderName, callback) {
   chrome.bookmarks.getTree(function(result) {
       var res = findFolderRecursive(folderName, result[0]);
       
       if (res == undefined) {
            chrome.bookmarks.create({
                'parentId': bookmarksBar,
                'title': folderName }, function(newbookmark) {
                   callback(newbookmark.id);
                });
       } else {
          callback(res);
       }
   });
}

function findFolderRecursive(folderName, treeNode) {
   if (treeNode.title == folderName) {
      return treeNode.id;
   } else if (treeNode.children) {
       for (var i = 0; i< treeNode.children.length; i++) {
           var res = findFolderRecursive(folderName, treeNode.children[i]);
           if (res != undefined) {
              return res;
           }
       }
   }
   return undefined;
}

function foldersFirst(treeNode, len) {
  //console.log("foldersFirst: treeNode="+treeNode.title);
    if (treeNode.url) {
      chrome.bookmarks.move(treeNode.id, {"parentId":treeNode.parentId, "index":len})
    } else if (treeNode.children) {
      for (var i = 0; i< treeNode.children.length; i++)
	foldersFirst(treeNode.children[i], treeNode.children.length);
    }
}


function getNodes(node) {   
   chrome.bookmarks.getTree(function(results) {
       otherBookmarks = results[0].children[1].id;
       bookmarksBar = results[0].children[0].id;
    findFolder(userFolderName, function(result) {
        userFolder = result;
        if (userFolderName == "Bookmarks bar") {
            userFolder = bookmarksBar;
        } else if (userFolderName == "Other bookmarks") {
            userFolder = otherBookmarks;
        }

        if (userFolderName == "Google Bookmarks") {
            deleteFolderId(userFolder, function() {
                bookmarksTree = getTreeNode("root", undefined);
                getNodesRecursive(node, bookmarksTree);

                //      console.log(bookmarksTree);
                createBookmarkTreeNoRoot(bookmarksTree, userFolder);
		chrome.bookmarks.getSubTree(userFolder, function (results) {foldersFirst(results[0], results[0].children.length)});
                window.clearTimeout(check_timer);
                check_timer = window.setTimeout(requestBookmarks, checkfrequency * 60 * 1000);
            });
        } else {
            deleteBookmarks(function() {
                bookmarksTree = getTreeNode("root", undefined);
                getNodesRecursive(node, bookmarksTree);

                //        console.log(bookmarksTree);
                createBookmarkTreeNoRoot(bookmarksTree, userFolder);
		chrome.bookmarks.getSubTree(userFolder, function (results) {foldersFirst(results[0], results[0].children.length)});
                window.clearTimeout(check_timer);
                check_timer = window.setTimeout(requestBookmarks, checkfrequency * 60 * 1000);
            });
        }
        
    });
     });
}

function getNodesRecursive(node, tree) {
    var nodeSet = document.evaluate("//bookmark", node, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);

    var node;
    while (node = nodeSet.iterateNext()) {
        var title = document.evaluate("title/text()", node, null, XPathResult.STRING_TYPE, null).stringValue;
        var url = document.evaluate("url", node, null, XPathResult.STRING_TYPE, null).stringValue;
        var labels = document.evaluate(".//label", node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
        var date = document.evaluate("timestamp", node, null, XPathResult.NUMBER_TYPE, null).numberValue;

        if (labels.snapshotLength == 0) {
            var myNode = getTreeNode(title, url, date);
            addTreeNode(tree, [userFolderName], myNode);
        } else {
            for (var i = 0; i < labels.snapshotLength; i++) {
                var label = labels.snapshotItem(i);
                var myNode = getTreeNode(title, url, date);
                addTreeNode(tree, label.textContent.split(delimiter), myNode);
            }
        }
    }
}

/* Actions */

function loadOptions() {
    var firstRun;

    console.log("Loading options");

    if (localStorage["delimiter"] != null)
      delimiter = localStorage["delimiter"];
    localStorage["delimiter"] = delimiter;

    if (localStorage["sortorder"] != null)
      sortorder = localStorage["sortorder"];
    localStorage["sortorder"] = sortorder;

    if (localStorage["checkfrequency"] != null && !Number(localStorage["checkfrequency"]).NaN) {
      checkfrequency = Number(localStorage["checkfrequency"]);
      if ( checkfrequency < 5)
	checkfrequency = 5;
    }
    localStorage["checkfrequency"] = checkfrequency;

    if (localStorage["folder"] != null)
      userFolderName = localStorage["folder"];
    localStorage["folder"] = userFolderName;

    if (localStorage["show"] != null)
      showPageAction = localStorage["show"];
    localStorage["show"] = showPageAction;
    
    if(localStorage["oldnodes"] != null) {
      try {
	JSON.parse(localStorage["oldnodes"]);
      } catch (e) {
	localStorage["oldnodes"] = "[]";
      }
    } else {
      localStorage["oldnodes"] = "[]";
    }
    oldNodes = JSON.parse(localStorage["oldnodes"]);
}

function saveOptions(data) {
  var res = false;

  console.log("Saving options");

  if (localStorage["checkfrequency"] != data.checkfrequency.toString()) {
    localStorage["checkfrequency"] = data.checkfrequency;
    res = true;
  }
  localStorage["delimiter"] = data.delimiter;
  localStorage["sortorder"] = data.sortorder;
  localStorage["folder"] = data.folder;
  localStorage["show"] = data.show;

  return res;
}

function requestBookmarks() {
    console.log("Refreshing bookmarks at " + Date().toLocaleString());

    if (userFolder)
    chrome.bookmarks.getSubTree(userFolder, function (results) {
	  oldNodes = results;
	  localStorage["oldnodes"] = JSON.stringify(results);
	  console.log("Old bookmarks saved!");
    });
    
    var xhr = new XMLHttpRequest();
    try {
        console.log("request..");
        xhr.onreadystatechange = function() {
            console.log("readystate: " + xhr.readyState);
            if ((xhr.readyState == 4) && (xhr.status == 200)) {
               if (xhr.responseXML) {
                    console.log("response..");
                    loggedIn = true;
                    window.clearTimeout(timerId);
                    var doc = xhr.responseXML;

                    getNodes(doc);
                    window.setTimeout(updateStars, 100);
               }
            }
        }

        xhr.onerror = function(error) {
            console.log("error: " + error);
            window.setTimeout(requestBookmarks, poll_timeout);
        }

        xhr.open("GET", gbookmarks_href, true);
        xhr.send(null);

        // Give up after giveUp_timeout
        var timerId = window.setTimeout(function() {
	    console.log("Cannot load bookmarks for "+giveUp_timeout+" ms. Giving up. Next try in "+poll_timeout+" ms");
            loggedIn = false;
            window.setTimeout(requestBookmarks, poll_timeout);
            xhr.abort();
            updateStars();
        }, giveUp_timeout);
    } catch (e) {
        console.log("ex: " + e);
        console.error("exception: " + e);
        window.setTimeout(requestBookmarks, poll_timeout);
    }
}